﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace Athena.ProxyGenerator.Implementaions
{
    using Convertible;
    using ExceptionHandler;
    using Runtime.Client;
    public class ServiceProxyFactory : IServiceProxyFactory
    {
        private IEnumerable<Type> _proxyInstanceCache;
        private readonly ConcurrentDictionary<RuntimeTypeHandle, object>
             _proxyServiceInstanceCache = new ConcurrentDictionary<RuntimeTypeHandle, object>();

        private readonly IServiceProxyGenerater _serviceProxyGenerater;
        private readonly IRpcInvokeService _rpcInvokeService;
        private readonly ITypeConvertibleService _typeConvertibleService;

        public ServiceProxyFactory(IServiceProxyGenerater serviceProxyGenerater, IRpcInvokeService rpcInvokeService, ITypeConvertibleService typeConvertibleService)
        {
            _serviceProxyGenerater = serviceProxyGenerater;
            _rpcInvokeService = rpcInvokeService;
            _typeConvertibleService = typeConvertibleService;
        }

        public void RegisteProxyType(IEnumerable<Type> needProxyTypes)
        {
            var clientServiceProxyKeyTypeOf = typeof(IClientServiceProxyKey);
            var noAssignableTypes = needProxyTypes.Where(x => !clientServiceProxyKeyTypeOf.IsAssignableFrom(x));
            if (noAssignableTypes.Count() > 0)
            {
                throw new RpcException(AthenaRpcInvokeResultCodeDisplay.RpcException, $"生成代理类型失败，{noAssignableTypes.First().Name}未继承于{nameof(IClientServiceProxyKey)}");
            }
            _proxyInstanceCache = _serviceProxyGenerater.GeneratorProxys(needProxyTypes);
        }

        public object CreateProxy(Type type)
        {
            if (_proxyInstanceCache == null || _proxyInstanceCache.Count() <= 0)
            {
                throw new RpcException(AthenaRpcInvokeResultCodeDisplay.RpcException, $"生成代理类型失败，尚未初始化{nameof(IServiceProxyFactory)}，或{nameof(type)}未继承于{nameof(IClientServiceProxyKey)}");
            }
            return _proxyServiceInstanceCache.GetOrAdd(type.TypeHandle, (typeHandle) =>
             {
                 var proxyType = _proxyInstanceCache.Single(type.IsAssignableFrom);

                 if (proxyType == null)
                 {
                     throw new RpcException(AthenaRpcInvokeResultCodeDisplay.RpcException, $"生成代理类型失败，{nameof(type)}未继承于{nameof(IClientServiceProxyKey)}");
                 }
                  return proxyType.GetConstructors().First().Invoke(new object[] { _rpcInvokeService, _typeConvertibleService });
             });
        }

        public T CreateProxy<T>()
        {
            return (T)CreateProxy(typeof(T));
        }
    }
}
